from datetime import datetime, timedelta
from fastapi import Depends, FastAPI, Request
from fastapi.security import SecurityScopes
from fastapi.security.oauth2 import OAuth2PasswordBearer
from fastapi.exceptions import HTTPException
from core.logger import logger
from curd.user_curd import ctrl_user
from core.utils import get_app_instance, get_request
import jwt

from settings import settings

OAuth2 = OAuth2PasswordBearer(settings.SWAGGER_UI_OAUTH2_REDIRECT_URL)


def create_access_token(data: dict):
    logger.debug(data)
    token_data = data.copy()
    # token超时时间
    expire = datetime.utcnow() + timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES)
    # 向jwt加入超时时间
    token_data.update({"exp": expire})
    # jwt加密
    jwt_token = jwt.encode(token_data, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
    logger.debug(jwt_token)
    return jwt_token


async def get_current_user(req: Request=Depends(get_request), token:str=Depends(OAuth2), app: FastAPI=Depends(get_app_instance)):
    logger.debug(token)
    if await app.state.cache.get(token):
        raise HTTPException(403, "Auth Detail, Token Expired")
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            algorithms=[settings.JWT_ALGORITHM]
        )
    except jwt.ExpiredSignatureError:
        logger.error('Signature has expired.')
        raise HTTPException(403, "Auth Detail")
    except jwt.DecodeError:
        logger.error('Error decoding signature.')
        raise HTTPException(403, "Auth Detail")
    user_name = payload["username"]
    logger.debug(payload)
    me = await ctrl_user.model.filter(username=user_name).first()
    if me:
        req.state.user_id = me.id
    else:
        raise HTTPException(403, "Auth Detail")
    return me
        


async def get_role_permission(user=Depends(get_current_user)):
    permission_list = []
    for role in await user.role.all():
        for access in await role.access.all():
            permission_list.append(access.permission_name)
    return permission_list
    

async def check_access(scope_list: SecurityScopes, permission_list=Depends(get_role_permission)):
    logger.debug(permission_list)
    logger.debug(scope_list.scopes)
    for scope in scope_list.scopes:
        if not scope in permission_list:
            raise HTTPException(401, "Permission Detail")
